contents
1. Java 멀티스레딩: 핵심 개념 및 스레드 생성
A. 멀티스레딩이란?
- 멀티스레딩은 하나의 프로그램(프로세스) 안에서 여러 "스레드"를 동시에 실행하여 작업 효율, 반응성, 리소스 활용을 높여주는 기법입니다.
- CPU, 네트워크, I/O 작업이 병렬로 효과적으로 수행될 때 특히 유용합니다.
B. 스레드 생성 방법
1. Thread 클래스 상속
class MyThread extends Thread {
public void run() {
System.out.println("Thread is running");
}
}
public class Main {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start(); // run()이 새로운 스레드에서 실행됨
}
}
2. Runnable 인터페이스 구현
class MyRunnable implements Runnable {
public void run() {
System.out.println("Running via Runnable");
}
}
public class Main {
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable());
t1.start();
}
}
3. ExecutorService 사용 (실무 추천)
- 스레드풀(thread pool)로 여러 스레드를 효율적으로 관리합니다.
import java.util.concurrent.*;
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 0; i < 3; i++) {
executor.submit(() -> System.out.println("Task executed by: " + Thread.currentThread().getName()));
}
executor.shutdown();
4. Callable & Future (결과 반환 필요할 때)
import java.util.concurrent.*;
Callable<Integer> task = () -> 123;
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(task);
Integer result = future.get(); // 결과값 123 반환 (대기)
executor.shutdown();
2. 스레드 동기화 및 동시성 제어
- 공유 데이터 보호를 위한 synchronized 키워드 또는 블록 사용.
- 명시적 락:
ReentrantLock,ReadWriteLock. - 조건 변수:
wait(),notify(). - 원자적 클래스:
AtomicInteger,AtomicReference. - 동시성 유틸리티:
CountDownLatch,CyclicBarrier,Semaphore등.
3. 스레드 라이프사이클 및 제어
- 주요 상태: New, Runnable, Running, Blocked/Waiting, Dead.
- 스레드 조정:
sleep(),join(),yield()등 사용.
4. Spring 및 Spring Boot에서의 멀티스레딩
Spring은 비동기 프로그래밍을 더욱 쉽고 안전하게 지원하는 추상화 계층을 제공합니다.
A. @Async 활용 (비동기 실행)
@Service
public class AsyncService {
@Async
public void performAsyncTask() {
System.out.println("Async task executed by: " + Thread.currentThread().getName());
}
}
@EnableAsync를 설정 클래스에 적용해야 함:
@Configuration
@EnableAsync
public class AsyncConfig {}
@Async메서드는 public 이어야 하며, 외부에서 호출되어야 동작합니다.
B. 스레드풀 구성 커스터마이징
ThreadPoolTaskExecutor로 풀 크기, 큐 크기 등을 설정 가능:
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(500);
executor.initialize();
return executor;
}
}
C. 동기화 & 트랜잭션 안전성
- Java의
synchronized혹은 명시적 락을 병렬 안전이 필요한 코드에 사용. - DB 연산 시 Spring의
@Transactional로 동시성 문제를 예방.
D. 스케줄링 & 배치 병렬 처리
@Scheduled로 주기적 비동기 작업 처리.- Spring Batch에서는
TaskExecutor로 Step 병렬화 처리.
5. 멀티스레딩 베스트 프랙티스
- 직접 스레드 생성 대신 스레드풀(
ExecutorService,ThreadPoolTaskExecutor) 우선 사용. - 상태 없는(Stateless) Bean 설계가 스레드 안전에 유리.
- 비동기 코드 내 예외 처리를 반드시 수행(예외 로깅 및 적절한 전파 필요).
- 동시성 버그는 매우 미묘할 수 있으니 철저한 테스트 필수.
java.util.concurrent제공 동시성 유틸리티 활용.
요약 비교 표
| 기법 | Java | Spring & Spring Boot |
|---|---|---|
| 스레드 기본 생성 | Thread, Runnable, ExecutorService | N/A (ExecutorService 권장) |
| 비동기 실행 | ExecutorService, Future | @Async, 스케줄러, Executor |
| 스레드풀 구성 | Executors, 직접 풀 크기 조정 | ThreadPoolTaskExecutor |
| 동기화/락 | synchronized, 명시적 락 | synchronized, 락, 트랜잭셔널 |
| 동시성 유틸리티 | CountDownLatch, Semaphore 등 | 모든 Java 동시성 유틸리티 활용 |
멀티스레딩은 빠르고 확장성 높은 Java/Spring 앱 구축의 핵심 요소입니다. 내장 추상화와 스레드풀을 적극 사용하여 병렬 처리를 구현하고, 언제나 스레드 안전과 자원 경합 문제를 최우선으로 고려해야 합니다.
references